package github.sf.fw.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;
import java.util.function.Function;


public abstract class ExceptionUtils {
    private final static Logger logger = LoggerFactory.getLogger(ExceptionUtils.class);

    private ExceptionUtils() {
    }

    public static <T> T errorApply(ThrowMethod<T> throwMethod, Consumer<Throwable> errorHandler) {
        try {
            return throwMethod.invokeMethod();
        } catch (Throwable e) {
            errorHandler.accept(e);
        }
        return null;
    }

    public static <T> T defaultApply(ThrowMethod<T> throwMethod) {
        return errorApply(throwMethod, (e) -> {
            throw new RuntimeException(e);
        });
    }

    public static void defaultVoid(ThrowVoidMethod throwMethod) {
        errorApply(() -> {
            throwMethod.invokeMethod();
            return null;
        }, (e) -> {
            throw new RuntimeException(e);
        });
    }

    public static <T, R, E extends Exception> Function<T, R> map(
            ThrowingFunction<T, R, E> throwingFunction) {
        return i -> {
            try {
                return throwingFunction.accept(i);
            } catch (Exception e) {
                logger.error("execute failed,reason:", e);
                throw new RuntimeException(e.getCause());
            }
        };
    }

    public interface ThrowMethod<T> {
        T invokeMethod() throws Throwable;
    }

    public interface ThrowVoidMethod {
        void invokeMethod() throws Throwable;
    }

    @FunctionalInterface
    public interface ThrowingFunction<T, R, E extends Exception> {
        R accept(T t) throws E;
    }
}
